﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TiposComuns.Objectos;
using System.Runtime.CompilerServices;

namespace Servidor.Objectos.Pesquisa
{
    /// <summary>
    /// Represents a list of people that have a particular property
    /// and the continuation of this list.
    /// </summary>
    [Serializable]
    public class SearchResult
    {
        #region Attributes
        private List<Person> results;
        private List<Person> removals;
        private byte[] contKey;
        private KClosest nexts;
        private byte[] key;

        public List<Person> Results
        {
            get { return results; }
            set { results = value; }
        }

        public List<Person> Removals
        {
            get { return removals; }
            set { removals = value; }
        }

        public byte[] ContKey
        {
            get { return contKey; }
            set { contKey = value; }
        }

        public byte[] Key
        {
            get { return key; }
            set { key = value; }
        }

        public KClosest Nexts
        {
            get { return nexts; }
            set { nexts = value; }
        }

        #endregion

        #region Constructors

        public SearchResult()
        {
            this.key = new byte[1];
            this.results = new List<Person>();
        }
        public SearchResult(byte []key)
        {
            this.key = key;
            this.results = new List<Person>();
            this.removals = new List<Person>();
        }

        public SearchResult(SearchResult sr)
        {
            this.key = (byte[])sr.key.Clone();

            this.results = new List<Person>();
            foreach (Person person in sr.results)
            {
                this.results.Add(person.Clone());
            }

            this.removals = new List<Person>();
            foreach (Person person in sr.removals)
            {
                this.removals.Add(person.Clone());
            }

            if (sr.nexts != null)
            {
                SortedArray closest = new SortedArray(KBucket.K);
                for(int i = 0;i<sr.nexts.Nodes.Lenght;i++)
                {
                    Person rem;
                    closest.Add(sr.nexts.Nodes.Keys[i],sr.nexts.Nodes.Array[i].Clone(),out rem);
                }

                this.nexts = new KClosest(sr.key,closest);
                this.contKey = sr.contKey;
            }
        }
        #endregion

        #region Methods
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Add(Person person)
        {
            if (this.results.Count < SearchedNodes.MAX)
            {
                this.results.Add(person);
            }
        }
        [MethodImpl(MethodImplOptions.Synchronized)]
        public bool IsFull()
        {
            return (this.results.Count == SearchedNodes.MAX);
        }
        [MethodImpl(MethodImplOptions.Synchronized)]
        public bool Contains(Person person)
        {
            return this.results.Contains(person);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Remove(Person person)
        {
            if (this.results.Remove(person))
            {
                this.removals.Add(person);
            }
        }
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void SetNexts(byte []contKey, KClosest nexts)
        {
            this.contKey = contKey;
            this.nexts = nexts;
        }

        public bool HasNexts()
        {
            return this.nexts != null;
        }
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Merge(SearchResult sr)
        {
            List<Person> res = new List<Person>();
            
            foreach (Person person in sr.removals)
            {
                this.results.Remove(person);
            }
            foreach (Person person in this.removals)
            {
                sr.results.Remove(person);
            }

            foreach (Person person in sr.results)
            {
                this.results.Remove(person);
                res.Add(person);
            }
            foreach (Person person in this.results)
            {
                res.Add(person);
            }

            this.results = res;
            sr.results = res;

            if (this.nexts == null)
            {
                this.contKey = sr.contKey;
                this.nexts = sr.nexts;
            }
            else
            {
                sr.contKey = this.contKey;
                sr.nexts = this.nexts;
            }
        }
        #endregion        
    }
}
